/**
 * 数据集合名称接口
 * @see sql数据库中的表
 */
export interface ICollectionInfo {
	/** 集合名称 */
	name: string;
	/** 是否使用内存表 */
	inmemory?: boolean;
}

/** 数据集合名称类 */
export class CollectionInfo implements ICollectionInfo {
	/** 集合名称 */
	public name: string = '';
	/** 是否使用内存表 true使用 false 不使用*/
	public inmemory?: boolean = false;
	/**
	 * 构造函数
	 * @param name 集合名称
	 * @param inmemory 是否使用内存表
	 */
	constructor(name:string , inmemory?:boolean){
		this.name = name;
		this.inmemory = inmemory;
	}
}

/** 管理nedb数据库类 */
export class ManageNeDB {
	/** 数据库集合类 */
	private _collections: any | Object = {};
	/** NeDB数据商店 */
	private DateStore = require('nedb');

	/**
	 * 构造函数
	 * @param tableinfos 表文档对象或对象数组
	 * @param filepath 数据库保存路径
	 * @see 保存路径不带后面的'/'
	 * @returns nedb管理类
	 */
	constructor(collectioninfos: Array<ICollectionInfo>, filepath?: string) {
		try {
			let _filepath = './databases';
			if (filepath) {
				_filepath = filepath;
			}
			for (let i = 0; i < collectioninfos.length; i++) {
				let collectioninfo = collectioninfos[i] as ICollectionInfo;
				if (!collectioninfo.inmemory) {
					collectioninfo.inmemory = false;
				}
				let opt: any = {
					filename: _filepath + '/' + collectioninfo.name + '.nedb',
					// timestampData: true,
					inMemoryOnly: collectioninfo.inmemory,
				};
				this._collections[collectioninfo.name] = new this.DateStore(opt);
				this._collections[collectioninfo.name].persistence.setAutocompactionInterval(5000);
			}
		} catch (err) {
			if (err) {
				throw new Error(err);
			}
		}
	}

	/**
	 * 数据库打开
	 * @returns true 打开成功 false 打开失败
	 */
	Open() {
		return new Promise((resovlve, reject) => {
			try {
				for (let collectionname in this._collections) {
					this._collections[collectionname].loadDatabase((err: any) => {
						if (err) {
							reject(false);
						}
					});
					this._collections[collectionname].persistence.setAutocompactionInterval(5000);
				}
				resovlve(true);
			} catch (err) {
				reject(false);
			}
		});
	}

	/** 关闭数据库
	 * @returns true 关闭成功 false 关闭失败
	 */
	Close() {
		return new Promise((resovlve, reject) => {
			try {
				if (this._collections) {
					this._collections = null;
				}
				resovlve(true);
			} catch (err) {
				reject(false);
			}
		});
	}

	/**
	 * 添加文档
	 * @param collectionname  集合名
	 * @param document  添加文档
	 * @returns true 添加成功 false 添加失败
	 */
	Add(collectionname: string, document: object | Array<object>) {
		return new Promise((resovlve, reject) => {
			try {
				this._collections[collectionname].insert(document, (err: any, newdoc: any) => {
					if (err) {
						reject(false);
					}
					resovlve(true);
				});
			} catch (err) {
				reject(false);
			}
		});
	}

	/**
	 * 同步添加文档
	 * @param collectionname 集合名
	 * @param document 添加文档
	 * @returns true 同步添加成功 false 同步添加失败
	 */
	AddSync(collectionname: string, document: object | Array<object>) {
		let self = this;
		return new Promise((resovlve, reject) => {
			try {
				this.Add(collectionname, document)
					.then(() => {
						return this.SyncTable(collectionname);
					})
					.then(() => {
						resovlve(true);
					})
					.catch(() => {
						reject(false);
					});
			} catch (err) {
				reject(false);
			}
		});
	}

	/**
	 * 删除数据
	 * @param collectionname 集合名
	 * @param query 删除条件
	 * @returns 删除记录条数，如果失败返回0值
	 */
	Remove(collectionname: string, query: object) {
		return new Promise((resovlve, reject) => {
			try {
				this._collections[collectionname].remove(query, { multi: true }, (err: any, removednum: any) => {
					if (err) {
						console.log(err);
						reject(0);
					}
					resovlve(removednum);
				});
			} catch (err) {
				console.log(err);
				reject(0);
			}
		});
	}

	/**
	 * 同步删除数据
	 * @param collectionname 集合名
	 * @param query 删除条件
	 * @returns 删除记录条数，如果失败返回0值
	 */
	RemoveSync(collectionname: string, document: object) {
		return new Promise((resovlve, reject) => {
			try {
				let _removenum: number = 0;
				this.Remove(collectionname, document)
					.then((removenum: any) => {
						_removenum = removenum;
						return this.SyncTable(collectionname);
					})
					.then(() => {
						resovlve(_removenum);
					})
					.catch(err => {
						reject(0);
					});
			} catch (err) {
				reject(0);
			}
		});
	}

	/**
	 * 更新数据
	 * @param collectionname 集合名
	 * @param query 更新条件
	 * @param updatedocument 更新文档
	 * @returns 更新记录条数，如果失败返回0值
	 */
	Update(collectionname: string, query: object, updatedocument: object) {
		return new Promise((resovlve, reject) => {
			try {
				this._collections[collectionname].update(
					query,
					updatedocument,
					{ multi: true },
					(err: any, updatenum: any, updatedoc: any, u: any) => {
						if (err) {
							reject(0);
						}
						resovlve(updatenum);
					}
				);
			} catch (err) {
				reject(0);
			}
		});
	}

	/**
	 * 同步更新数据
	 * @param collectionname 集合名
	 * @param query 更新条件
	 * @param updatedocument 更新文档
	 * @returns 更新记录条数，如果失败返回0值
	 */
	UpdateSync(collectionname: string, query: object, updatedocument: object) {
		return new Promise((resovlve, reject) => {
			try {
				let _num: number = 0;
				this.Update(collectionname, query, updatedocument)
					.then((num: number) => {
						_num = num;
						return this.SyncTable(collectionname);
					})
					.then(() => {
						resovlve(_num);
					})
					.catch(err => {
						reject(0);
					});
			} catch (err) {
				reject(false);
			}
		});
	}

    /**
     * 查询数据
     * @param collectionname 集合名
     * @param query 查询条件
     * @param sort 排序条件 如果为空则不排序
     * @param skip 本次跳过记录条数，如果为空则不跳过
     * @param limit 本次读取记录条数，如果为空则读取全部
     * @returns 查询对象数组
     */
	Find(collectionname: string, query: object, sort?: object, skip?: number, limit?: number) {
		return new Promise((resovlve, reject) => {
			try {
				let _find = this._collections[collectionname].find(query);
				if (sort) {
					_find.sort(sort);
				}

				if (skip) {
					_find.skip(skip);
				}

				if (limit) {
					_find.limit(limit);
				}
				_find.exec((err: any, finddoc: any) => {
					if (err) {
						console.log(err);
						reject([]);
					}
					if (!Array.isArray(finddoc)) {
						finddoc = [finddoc];
					}
					resovlve(finddoc);
				});
			} catch (err) {
				console.log(err);
				reject([]);
			}
		});
	}

    /**
     * 查询统计数据
     * @param collectionname 集合名
     * @param query 查询条件
     * @returns 统计数据，如果失败或异常返回0
     */
	FindCount(collectionname: string, query: object) {
		return new Promise((resovlve, reject) => {
			try {
				let _count = this._collections[collectionname].count(query);
				_count.exec((err: any, findcount: any) => {
					if (err) {
						console.log(err);
						reject(0);
					}
					resovlve(findcount);
				});
			} catch (err) {
				console.log(err);
				reject(0);
			}
		});
	}

    /**
     * 同步整理表
     * @param collectionname 集合名
     * @returns true 同步整理成功 false 同步整理失败
     */
	SyncTable(collectionname: string) {
		return new Promise((resovlve, reject) => {
			try {
				this._collections[collectionname].persistence.compactDatafile();
				this._collections[collectionname].once('compaction.done', () => {
					resovlve(true);
				});
			} catch (err) {
				reject(false);
			}
		});
	}
}
